package com.fzk.controller;

import com.fzk.core.FileMetaStore;
import com.fzk.core.FileStoreService;
import com.fzk.core.btree.Page;
import com.fzk.exception.IllegalParamsException;
import com.fzk.router.AutoRegister;
import com.fzk.router.MyAutowire;
import com.fzk.router.MyRequestMapping;
import com.fzk.router.SimpleApiHandler;
import com.fzk.server.MyHttpUtil;
import com.fzk.utils.MyCollectionUtil;
import com.fzk.utils.MyFileUtil;
import com.fzk.vo.CheckAck;
import com.fzk.vo.FileDetail;
import com.fzk.vo.HttpResult;
import io.netty.handler.codec.http.HttpResponseStatus;
import lombok.Data;

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@SuppressWarnings("unused")
@AutoRegister
public class FileServiceController {
    @MyAutowire(key = "fileService")
    private FileStoreService fileService;

    @MyRequestMapping(path = "/fs/api/prefixSearchCount", method = "GET")
    private final SimpleApiHandler prefixMatchCount = (ctx,request, params) -> {
        if (params.containsKey("prefix") && params.get("prefix").size() == 1) {
            int count = fileService.prefixSearchCount(params.get("prefix").get(0));
            return HttpResult.success(count);
        } else {
            return new HttpResult(HttpResponseStatus.BAD_REQUEST.code(), "参数错误", null);
        }
    };

    @MyRequestMapping(path = "/fs/api/prefixSearch", method = "GET")
    public final SimpleApiHandler prefixMatch = ((ctx,request, params) -> {
        if (params.containsKey("prefix") && params.containsKey("page") && params.containsKey("size")) {
            int page = Integer.parseInt(params.get("page").get(0));
            int size = Integer.parseInt(params.get("size").get(0));
            if (page <= 0 || size <= 0) {
                return new HttpResult(HttpResponseStatus.BAD_REQUEST.code(), "参数错误", null);
            }
            ArrayList<Page.BEntry> result = fileService.prefixSearch(params.get("prefix").get(0), (page - 1) * size, size);
            return HttpResult.success(result);
        } else {
            return new HttpResult(HttpResponseStatus.BAD_REQUEST.code(), "参数错误", null);
        }
    });

    // 目录文件列出
    @MyRequestMapping(path = "/fs/api/dirFileList", method = "GET")
    public final SimpleApiHandler dirFileList = ((ctx,request, params) -> {
        if (params.containsKey("dir")) {
            Path dir = Path.of(params.get("dir").get(0));
            if (Files.isDirectory(dir)) {
                try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
                    ArrayList<FileDetail> result = new ArrayList<>();
                    stream.forEach((p) -> {
                        FileDetail fileDetail;
                        if (Files.isDirectory(p)) {
                            fileDetail = new FileDetail(null, true, false, p.getFileName().toString(), MyFileUtil.toUnixPath(p.toString()), null, null);
                        } else {
                            String key = FileStoreService.generateKey(p, fileService.dataDir);
                            FileMetaStore.FileMetaWrapper fileMeta = fileService.getFileMeta(key);
                            if (fileMeta != null) {
                                fileDetail = new FileDetail(key, false, MyFileUtil.isImage(p), p.getFileName().toString(), MyFileUtil.toUnixPath(p.toString()), fileMeta.meta, MyFileUtil.fileSizeInfo(fileMeta.meta.getSize()));
                            } else {
                                fileDetail = new FileDetail(key, false, MyFileUtil.isImage(p), p.getFileName().toString(), MyFileUtil.toUnixPath(p.toString()), null, "");
                            }
                        }
                        if (fileDetail.path.contains("#")) {// 若路径中包含#，会被浏览器识别为定位锚点符
                            fileDetail.path = fileDetail.path.replace("#", URLEncoder.encode("#", StandardCharsets.UTF_8));
                        }
                        result.add(fileDetail);
                    });
                    // 排个序方便前端展示
                    FileDetail[] details = result.toArray(FileDetail[]::new);
                    // 将目录放在前面，将图片尽可能的放在后面
                    Arrays.sort(details, (a, b) -> {
                        if (a.isDir && b.isDir) {// 都是目录
                            return a.filename.compareTo(b.filename);
                        } else if (a.isDir || b.isDir) {// 有1个为目录
                            return a.isDir ? -1 : 1;
                        } else {// 都是文件
                            if (a.isImage && b.isImage) {// 都是图片
                                return a.filename.compareTo(b.filename);
                            } else if (a.isImage || b.isImage) {// 有一个为图片
                                return a.isImage ? 1 : -1;
                            } else {// 都不是图片
                                return a.filename.compareTo(b.filename);
                            }
                        }
                    });
                    return HttpResult.success(details);
                } catch (IOException e) {
                    ctx.error(String.format("打开目录流出错, dir: %s, err: %s", dir, e));
                    throw new RuntimeException(e);
                }
            } else {
                return new HttpResult(400, dir + " 不是目录或不存在", null);
            }
        } else {
            return new HttpResult(HttpResponseStatus.BAD_REQUEST.code(), "参数错误", null);
        }
    });

    @Data
    private static class DeleteFileArgs {
        public List<String> key;
        public String token;
    }

    @MyRequestMapping(path = "/fs/api/deleteFile", method = "POST")
    public final SimpleApiHandler deleteFile = ((ctx,request, params) -> {
        try {
            // 获取参数, 表单没有则从json拿
            List<String> keys = params.get("key");
            if (keys == null) {
                DeleteFileArgs p = MyHttpUtil.parseJsonParams(request, DeleteFileArgs.class);
                if (p != null) {
                    keys = p.key;
                }
            }
            if (MyCollectionUtil.isEmpty(keys)) {
                return new HttpResult(400, "参数key不能为空", null);
            }
            ctx.info(String.format("准备删除keys: %s", keys));
            ArrayList<FileMetaStore.FileMetaWrapper> list = new ArrayList<>();
            for (String key : keys) {
                list.add(fileService.deleteFile(key));
            }
            return HttpResult.success(list);
        } catch (IllegalParamsException e) {
            return new HttpResult(400, "invalid params: " + e.getMessage(), null);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    });

    @MyRequestMapping(path = "/fs/api/sliceCheck", method = "GET")
    public final SimpleApiHandler sliceCheck = ((ctx,request, params) -> {
        if (!(params.containsKey("bucket") && params.containsKey("relativePath") && params.containsKey("filename"))) {
            return new HttpResult(400, "缺少参数", null);
        }
        String bucket = params.get("bucket").get(0);
        String relativePath = params.get("relativePath").get(0);
        String filename = params.get("filename").get(0);
        if (bucket.length() == 0 || relativePath.length() == 0 || filename.length() == 0) {
            return new HttpResult(400, "缺少参数", null);
        }
        try {
            CheckAck ack = fileService.fileSliceCheck(bucket, relativePath, filename);
            return HttpResult.success(ack);
        } catch (IOException e) {
            ctx.error(String.format("断点检查出现io异常, bucket: %s, relativePath: %s, filename: %s, err: %s", bucket, relativePath, filename, e.getMessage()));
            e.printStackTrace();
            return new HttpResult(500, "服务异常: " + e.getMessage(), null);
        }
    });
}
